package com.itheima.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.mapper.EmpExprMapper;
import com.itheima.mapper.EmpLogMapper;
import com.itheima.mapper.EmpMapper;
import com.itheima.pojo.*;
import com.itheima.service.DeptService;
import com.itheima.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper,Emp> implements EmpService {

    @Autowired
    private DeptService deptService;

    @Autowired
    private EmpExprMapper empExprMapper;

    @Autowired
    private EmpLogMapper empLogMapper;

    /**
     * 分页查询
     *
     * @param page     页码
     * @param pageSize 记录数
     * @param param    封装的查询参数
     * @return 查询结果
     */
    @Override
    public PageResult<Emp> findPage(Integer page, Integer pageSize, EmpQueryParam param) {
        IPage<Emp> ipage = new Page<>(page, pageSize);
        LambdaQueryWrapper<Emp> wrapper = Wrappers.lambdaQuery();
        wrapper.like(!param.getName().equals(""), Emp::getName, param.getName())
                .eq(param.getGender() != null, Emp::getGender, param.getGender())
                .between(param.getBegin() != null && param.getEnd() != null, Emp::getEntryDate, param.getBegin(), param.getEnd())
                .orderByDesc(Emp::getUpdateTime);
        ipage = this.page(ipage, wrapper);
        List<Emp> records = ipage.getRecords();
        long total = ipage.getTotal();
        List<Integer> deptIds = records.stream().map(emp -> emp.getDeptId()).toList();
        //获取员工表中部门id
        deptIds = deptIds.stream().distinct().toList();
        //根据部门id集合查询部门
        if (!CollectionUtils.isEmpty(deptIds)) {
            List<Dept> depts = deptService.listByIds(deptIds);
            //双重for循环，实现为每一个emp实体对象中的deptName属性进行赋值
            // 遍历所有员工记录（records是员工列表，emp是循环中的每个员工对象）
            records.forEach(emp -> {
                // 从部门列表（depts）中筛选部门
                depts.stream()  // 将部门列表转换为流，便于进行筛选操作
                        .filter(dept -> dept.getId().equals(emp.getDeptId()))  // 过滤条件：部门ID与当前员工的部门ID相等
                        .findFirst()  // 获取符合条件的第一个部门（因为部门ID通常唯一，所以取第一个即可）
                        .ifPresent(dept -> {  // 如果找到了对应的部门（非空），就执行下面的操作
                            emp.setDeptName(dept.getName());  // 把部门的名称设置到员工对象中
                        });
            });
        }
        return new PageResult<>(total, records);
    }

    /**
     * 新增员工
     *
     * @param emp 员工以及员工的工作经历
     */
    //Spring 事务默认只对「运行时异常（RuntimeException）」和「错误（Error）」触发回滚，对「受检异常（Checked Exception）」不回滚。
    // rollbackFor = Exception.class 的效果只要方法中抛出「Exception 及其子类异常」（无论运行时异常还是受检异常），Spring 都会强制回滚事务，彻底覆盖了默认规则。
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveEmp(Emp emp) {
        try {
            //补全基本信息
            emp.setPassword("123456");
            emp.setCreateTime(LocalDateTime.now());
            emp.setUpdateTime(LocalDateTime.now());
            this.save(emp);
            //获取工作经历的集合
            List<EmpExpr> exprList = emp.getExprList();
            if(!CollectionUtils.isEmpty(exprList)) {
                //为每一段工作经历绑定对应的员工id
                exprList.forEach(empExpr -> empExpr.setEmpId(emp.getId()));
                //批量保存员工经历
                empExprMapper.insert(exprList);
            }
        } finally {
            EmpLog empLog = new EmpLog(null,LocalDateTime.now(),emp.toString());
            empLogMapper.insert(empLog);
        }
    }

    /**
     * 查询回显
     * @param id 员工id
     * @return 查询到的员工信息
     */
    @Override
    public Emp getInfo(Integer id) {
        // 1. 使用MyBatis-Plus通用方法，根据员工ID查询员工基本信息
        Emp emp = this.getById(id);
        // 2. 查询该员工对应的所有工作经历：通过Lambda查询条件，筛选工作经历表中empId等于当前员工ID的记录
        List<EmpExpr> empExprs = empExprMapper.selectList(Wrappers.<EmpExpr>lambdaQuery().eq(EmpExpr::getEmpId, emp.getId()));
        // 3. 将查询到的工作经历列表设置到员工实体的exprList属性中，完成数据关联
        emp.setExprList(empExprs);
        // 4. 返回包含工作经历的员工实体
        return emp;
    }

    /**
     * 修改员工
     * @param emp 员工以及员工经历的信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateEmp(Emp emp) {
        // 1. 更新员工的"最后修改时间"为当前时间
        emp.setUpdateTime(LocalDateTime.now());
        // 2. 调用MyBatis-Plus通用方法，根据员工ID更新员工基本信息
        this.updateById(emp);
        // 3. 先删除该员工原有的所有工作经历（因为修改时可能替换全部工作经历，先清旧数据）
        // 通过Lambda查询条件：删除emp_expr表中emp_id等于当前员工ID的所有记录
        empExprMapper.delete(Wrappers.<EmpExpr>lambdaQuery()
                // 条件：工作经历的员工ID=当前员工ID
                .eq(EmpExpr::getEmpId, emp.getId()));
        // 4. 获取新的工作经历列表
        List<EmpExpr> exprList = emp.getExprList();
        // 5. 如果新的工作经历列表不为空，则批量保存新的工作经历
        if(!CollectionUtils.isEmpty(exprList)) {
            // 5.1 为每条新工作经历绑定当前员工的ID
            exprList.forEach(empExpr -> empExpr.setEmpId(emp.getId()));
            // 5.2 批量插入新的工作经历
            empExprMapper.insert(exprList);
        }
    }

    /**
     * 删除员工
     * @param ids 需要删除的员工id
     */
    @Override
    public void delete(List<Integer> ids) {
        this.removeByIds(ids);
        empExprMapper.delete(Wrappers.<EmpExpr>lambdaQuery()
                // 删除多个员工的工作经历：用in条件，接收List参数
                .in(EmpExpr::getEmpId,ids));
    }
}
